 page
alcbuffr ldy #c.bufptr+1 ;index to user specified buffer
alcbufr1 lda (par),y ;this buffer must be on a page boundary. 
 tax ;save in x for validation
 cmp #$8 
 bcc obadbuf ;cannot be lower than video!
 cmp #$bc ;nor greater than $bb00
 bcs obadbuf ; since it would wipe out globals...
 sta datptr+1
 dey 
 lda (par),y ;low addr should be zero!
 sta datptr
 bne obadbuf ;branch if it isn't
 inx ;add 4 pages for 1k buffer 
 inx
 inx
 inx
alcbufr2 dex ;test for conflicts
 jsr cmembit ;test for free buffer space
 and memtabl,y ;report memory conflict.
 bne obadbuf ; if any...
 cpx datptr+1 ;test all four pages. 
 bne alcbufr2 
 inx ;add 4 pages again for allocation. 
 inx
 inx
 inx
alcbufr3 dex ;set proper bits to 1 
 jsr cmembit
 ora memtabl,y ; to mark it's allocation. 
 sta memtabl,y 
 cpx datptr+1 ;set all four pages. 
 bne alcbufr3 
 ldy fcbptr ;now calculate buffer number.
 lda fcb+fcbrefn,y
 asl a ;buffer number=(entnum)*2
 sta fcb+fcbfbuf,y ;save it in fcb.
 tax ;use entnum*2 as index to global buffer addr tables.
 lda datptr+1 ;get addr already validated as good.
 sta gl.buff-1,x ;store hi addr (entnums start at 1, not zero)
 clc
 rts ;all done allocating buffers.
*
obadbuf lda #badbuf ;tell user buffer is in use or not legal otherwise.
 sec ;indicate error.
 rts
*
getbufadr equ * 
 tax ;index into global buffer table.
 lda gl.buff-2,x ;low buffer addr
 sta bufaddrl
 lda gl.buff-1,x ;and high addr.
 sta bufaddrh
 rts
*
relbuffr jsr getbufadr ;preserve buf adr in 'bufaddr' 
 ora #$00 ;returns high buffer addr in acc.
 beq relbuf1 ;branch if unallocated buffer space. 
 lda #0 ;take address out of buffer list.
 sta gl.buff-1,x ;(x was set up by getbufadr) 
 sta gl.buff-2,x 
freebuf ldx bufaddrh ;get hi addr of buffer again. 
 inx ;add 4 pages to account for 1k space 
 inx 
 inx
 inx
frebuf1 dex ;drop to next lower page.
 jsr cmembit ;get bit and posn to memtabl of this page
 eor #$ff ;invert mask.
 and memtabl,y ;mark addr as free space now.
 sta memtabl,y 
 cpx bufaddrh ;all pages freed yet?
 bne frebuf1 ;branch if not.
relbuf1 clc ;indicate no error. 
 rts
*
* calculate memory allocation bit position
*  entry: x=hi addr of buffer, low addr assumed zero.
*
*  exit: acc=allocation bit mask, x=unchanged, y=pointer to memtabl byte.
*
cmembit txa ;move page address to acc. 
 and #7 ;which page in any 2k set? 
 tay ;use as index to determine 
 lda whichbit,y ; bit position representation. 
 pha ;save bit position mask for now.
 txa ;get page address again. 
 lsr a 
 lsr a ;now determine 2k set. 
 lsr a 
 tay ;return it in y. 
 pla ;restore bit mask. 
 rts ;return bit position in a&y, pointer to memtabl in x.
*
valdbuf lda usrbuf+1 ;get high addr of user's buffer
 cmp #2 ;must be greater than page 2
 bcc obadbuf ;report bad buffer.
 skp 1 
 ldx cbytes+1
 lda cbytes ;get cbytes-1 value.
 sbc #1 ;(carry is set)
 bcs vldbuf0
 dex
vldbuf0 clc
 adc usrbuf ;calculate end of request addr.
 txa ;do hi addr.
 adc usrbuf+1 ;all we care about is final addr.
 tax ;must be less than $bf (globals) 
 cpx #$bf
 bcs obadbuf
 inx ;loop thru all  affected pages.
vldbuf1 dex ;check next lower page.
 jsr cmembit
 and memtabl,y ;if zero then no conflict
 bne obadbuf ;branch if conflict... 
 cpx usrbuf+1 ;was that the last (lowest) page? 
 bne vldbuf1 ;branch if not. 
 clc ;indicate all pages ok.
 rts ;all done here
*
 page
getbuf ldy #c.bufadr ;give user address of file buffer
 lda bufaddrl ; referenced by refnum.
 sta (par),y
 iny
 lda bufaddrh
 sta (par),y ;no errors possible if this routine is called.
 clc
 rts
*
setbuf ldy #c.bufadr+1
 jsr alcbufr1 ;allocate new buffer address over old one
 bcs sbuferr ;report any conflicts immediately
 lda bufaddrh
 sta usrbuf+1
 lda bufaddrl
 sta usrbuf
 jsr freebuf ;now free address space of old buffer.
 ldy #0
 ldx #3
setbuf1 lda (usrbuf),y ;move all four pages of the buffer to new location.
 sta (datptr),y
 iny
 bne setbuf1
 inc datptr+1
 inc usrbuf+1
 dex
 bpl setbuf1
 clc ;indicate all is well...
sbuferr rts ;all done.
 page 
****************************************************
*
*  this is the routine that moves the 3 pages of dispatcher 1
*  from $d100 of the alt 4k bank to its execution address ($1000).
*  since it is in the mli and must swap the $d000-$dfff banks,
*  it must be resident at all times above $e000.
*
****************************************************
 skp 2
* prodos16 patches into this area.
* if this code moves from $fcd5 then
* prodos16 must change.
 skp 2
calldisp equ *
 lda ramin2
 lda ramin2 ;bring in the other $d000 space
 ldy #3
svzpg lda 0,y ;save zero page locations 0-3  
 pha  ;  since we will use them as pointers 
 dey
 bpl svzpg
 lda #<dispadr ;destination address of user-code 
 sta 3
 lda #$d1 ;dispatcher is stored at $d100-$d3ff 
 sta 1
 lda #0
 sta 0 
 sta 2
 tay ;y will be 0 now 
 ldx #3 ;3 pages of code to move
mvpge dey ;nifty routine to move a page of code
 lda (0),y ;move all 255 bytes on the page 
 sta (2),y
 tya
 bne mvpge
 inc 1 ;move pointers to next page 
 inc 3
 dex ;move all pages needed 
 bne mvpge
************************** see rev note #34 **********************
*pla ;restore the zero-page locations 
******************************************************************
* ldy #$fc ;use wraparound from $ffff to $0
* restzpg pla  ; to restore z-pg locations used.
* sta $ff04,y
* iny
* bne restzpg
* fall into this code with 'x'=$00
 skp 1
@1 equ *
 pla  ;recall zero page bytes
 sta $00,x ;
 inx  ;next byte please
 cpx #$04 ;move 4 only
 bcc @1 ;loop til done
 nop  ;keep code same length
 skp 2
* prodos16 bra's to here with code patched
* over code above.  if this code moves
* then prodos16 must change.
 skp 2
 lda ramin
 lda ramin ;swap mli's $d000 space back in.
 lda #>dispadr 
 sta reset ;set up the reset vector
 lda #<dispadr ;  to dispatch entry 
 sta reset+1
 eor #$a5 ;set up power up byte
 sta reset+2
 jmp dispadr
 page
* -------------------- see rev note 15 --------------------------
*  this is the (goadr) for a ram based driver located in the 
*    aux language card.  it must do housekeeping and then jsr
*    to auxgo.  upon return, status must be restored before
*    leaving with an rts.  
*
*  since it is in the mli and must swap the $d000-$dfff banks,
*    it must be resident at all times above $e000.
*
*********************************************************************
**                                                                 **
**  restriction: in order to absolutely tell a disk ][ with a      **
**   device id of 0 from a ram based driver with a device id of 0, **
**   this driver must not, repeat not, begin on a page boundary!   **
**                                                                 **
*********************************************************************
*
ramdrvr equ *
 php ;save the processor status
 pla ;get status into acc
 pha
 clv ;clear the overflow flag
 and #$4 ;check for interrupts disabled (flag on)
 beq *+5 ;branch to sei if not
 bit ramdrtn ;set overflow flag on if int flag was on
 sei ;disable interrupts since we are going to aux lc
 lda ramin2
 lda ramin2 ;swap in other $d000 space
 sec ;  and set carry as a process flag for
 ldx #$5 ;  lc.  get ready to move 5 param bytes,
 jsr auxgo ;  and then go!
*
*  ok, we're back (i hope) with error code in acc and error stat
*  in carry.
*
 sta serr ;save error code in serr
 lda ramin
 lda ramin ;restore first $d000 bank
 plp ;restore processor status
 clc
 lda serr ;in case call is direct & needs err code
 beq ramdrtn
 sec ;set carry on an error code not 0
ramdrtn rts ;  and return
*
 ifeq os-prodos
*
*********** see rev notes #20,#42 *****
*
*** dobus is the setup and caller for the atp driver.
*** since the driver resides in bank 2, this calling code must
*** reside at or above $e000.
*
dobus equ *
 sta ramin2 ; this should be all that is needed for b2 r/w.
 jsr network ; call the atp driver.
 sta ramin ; swap back bank 1 preserving status.
 rts  ; errors will be returned by driver.
***************************************
 fin
 ifeq os-ednet
*
************ see rev note #en3 *****************
*
bridge equ * 
*
*
* on entry the stack is assumed to look like the following:
*
*  processor status
*  a register
*  x register
*  return address hi
*  return address low
*
****
*
* input : a = offset into atalk entry address table.
* output : a = error code, carry set if error.  x,y not changed.
*
call.aux.dest equ $200 ; where call.aux routine will go.
*
*
 sei  ; no interrupts please...
 asl a ; a = a*2 for displacement into table.
 pha  ; save for later...
*
 inc call.level ; now update current entry level.
 bne skip.save ; only save routine on first entry.
*
 ldx #call.aux.len ; save off pg 2 area we are using...
saveoff lda call.aux.dest-1,x ;
 sta save.pg2-1,x ; save in local storage.
 dex  ;
 bne saveoff ;
*
 ldx #call.aux.len ; now put the call.aux routine
move.bridge lda call.aux-1,x ; at $200.
 sta call.aux.dest-1,x ;
 dex  ;
 bne move.bridge ;
*
skip.save equ *
*
 pla  ; now get x back..
 tax  ;
*
 lda bridge.flag ; save off locally used data 
 pha  ; on the stack to maintain re-entrancy.
 lda save.main.sp ;
 pha  ;
*
 lda atalktbl,x ; get low byte of address.
 sta entry.addrl ; move it to its proper place in 
 lda atalktbl+1,x ; the call.aux routine.
 sta entry.addrh ; move high byte in.
*
 tsx  ; now move x,a, and p values from stack
 lda $105,x ; to local storage so the call.aux
 sta savx ; routine can use them.
 lda $106,x ; now get a...
 sta sava ;
 lda $107,x ; now get p...
 sta savp ;
*
 jsr call.aux.dest ; now go do aux lc atalk routine!
*
*
 sta x.sava ; save a upon return from aux.
 dec call.level ; now update call level back one.
 bpl skip.restore ; restore only on first call.
*
 ldx #call.aux.len ; 
restore lda save.pg2-1,x ; restore page 2 area used...
 sta call.aux.dest-1,x ; 
 dex  ;
 bne restore ; branch if not done.
*
skip.restore pla  ; now restore local stuff from stack.
 sta save.main.sp ;
 pla  ;
 sta bridge.flag ;
 pla  ;
 sta return ;
 pla  ;
 sta return+1 ;
 pla  ;
 tax  ; 
 pla  ; discard original user's a.
 pla  ; discard original status.
 lda return+1 ; now prepare to return...
 pha  ;
 lda return ;
 pha  ;
 lda x.sava ; now recover a.
 rts  ; and that's all.
*
*
call.aux equ * ; this routine is relocatable and will run at $200.
*
* input: savx,y are assumed to have an address of a parameter list.
*        sava has an atalk command number.
* output: a = error code, carry set will indicate an error.
*
 sta $c009 ; switch in aux lc, zp, stack.
 bvs called.int ; if called from int, save stack locally.
 lda #00 ; indicate normal
 sta bridge.flag ; mode of entry
 tsx  ; put sp in x.
 stx $100 ; save main sp in $100 in alt stack.
 bvc common.stuff ;always taken
called.int equ * ;called from interrupt routine
 lda #1 ; indicate came through interrupt 
 sta bridge.flag ; routine
 tsx  ; get stack pointer
 stx save.main.sp ; save it for later
common.stuff equ * ;rest is common to both
no.stack.setup ldx $101 ; get aux sp
 txs  ; and set sp with it.
*
 lda #<return.addr-1 ; push return addr on
 pha  ; stack so control
 lda #>return.addr-1 ; will return after aux atalk
 pha  ; routine rts's.
*
*
x.entry.addrh equ *+1
 lda #0 ; ** self modified!
 pha  ; save aux entry address on stack.
x.entry.addrl equ *+1
 lda #0 ; ** self modified!
 pha  ;
*
x.savp equ *+1
 lda #0 ; ** self modified **
 pha  ; now restore interrupt status.
*
x.savx equ *+1
 ldx #0 ; * warning: self modified!
x.sava equ *+1
 lda #0 ; *warning: self modified!
entry.addr equ *+1
 rti  ; rti to aux while also enabling ints..
*
return.addr equ call.aux.dest+*-call.aux ; 
 sei  ; disable interrupts from here on out...
 tsx  ; save aux sp
 stx $101 ; at $101 in aux stack.
 ldx bridge.flag ; check to see how we got here
 bne from.int ; from an int
 ldx $100 ; get main sp back
 txs  ; into sp.
 sta $c008 ; switch in main lc
 rts  ; and return
from.int equ *
 ldx save.main.sp ; recover stack pointer
 txs  ; and set it up
 sta $c008 ; switch in main lc, zp, stack.
 rts  ; and return.
*
call.aux.len equ *-call.aux ; length of call.aux routine.
*
save.main.sp equ call.aux.dest+*-call.aux
 db 0 ; this temp must remain in main memory!
bridge.flag equ call.aux.dest+*-call.aux
 db 0 ; ditto! (used while alc in)
*
*
savx equ call.aux.dest+x.savx-call.aux
sava equ call.aux.dest+x.sava-call.aux
savp equ call.aux.dest+x.savp-call.aux
entry.addrh equ call.aux.dest+x.entry.addrh-call.aux
entry.addrl equ call.aux.dest+x.entry.addrl-call.aux
*
save.pg2 ds call.aux.len,0 ; save pg 2 used here.
call.level db $ff ; used to signify what call level we're at.
return dw $0000 ;
*
***********   rpm stub   **********
*
rpm.stub equ *
 txa  ; save x on the stack.
 pha  ;
*
 tsx  ; ** must inc return address so the
 inc $105,x ; rti will return correctly.
 bne skiphi ;
 inc $106,x ;
skiphi equ *
*
 clv  ; clear overflow flag to signify not from int.
 lda #2 ; offset for rpm.
 jsr bridge ; and go do it!
 jmp exitrpm ; go restore lc state and return.
*****************************************************
 fin
